Aspect
意思為剖面,Oriented
意思為導向,所以翻譯為剖面導向程式設計
,這意思恐怕很難直接從字面上理解,技術人員就直接用程式來說明吧。
一般我們在寫程式時,很常需要處理譬如錯誤紀錄
、權限驗證
,乃至於額外可能增加使用者查詢歷程
等等,就以錯誤紀錄來說,一個方法(Function)要用Nlog進行錯誤紀錄,通常會是這樣子。
public int TestFunction(int num1, int num2)
{
int result;
try{
result = num1 + num2;
}
catch (Exception ex){
var logger = LogManager.GetLogger(invocation.GetType().FullName);
logger.Error(ex, ex.Message);
}
return result;
}
如果系統不大,就那十幾個方法,複製貼上也就解決,但如果是個大系統,幾百個方法要寫的話,勤勞的人也許可以做幾百次複製貼上,但是生性懶惰的我根本不會想這樣蠻幹,而AOP這個架構的誕生,就是基於要減少類似這樣的重工。
畫個圖來看,一般我們寫的方法流程,基本是這個樣子的。
舉例,每個方法都有自己的兩個驗證機制以及一個錯誤處理,若是有200個方法的話就要做597次的重工,而改採用AOP的架構的話,驗證機制與錯誤處理只要各寫一次,其他方法只要在方法上或者是Service上加個標籤(Attribute),馬上省掉這597次的重工,而此時方法的流程就會呈現如下。
這個圖也就是AOP的中心思想,將直向流程的方法,抽離出共用邏輯,再將共通邏輯從側面橫切插入到原本的方法,透過AOP,我們可以達成軟體工程的兩個概念。
如果是.Net MVC專案的話,在Controller上可以透過ActionFilter
這個標籤來完成AOP的功能,但無法套用在普通的方法上,目前也沒有Nuget套件可以直接拿來用,要實作的話,可以用Autofac.Extras.DynamicProxy
的Intercept
(攔截)標籤,但是要額外加工,並且自訂Interceptor
(攔截器)的內容,攔截,顧名思義就是在方法執行的時候,先把方法暫停一下,可以取得他傳入的參數以及回傳值的類型,而攔截器定義的內容就是你要為方法進行甚麼樣的處理,例如錯誤紀錄。
使用Autofac的Intercept,在interface或service class上加上這樣的標籤,而方法內容只要專注於商業邏輯就好,如下。
using Autofac.Extras.DynamicProxy;
//例外處理的AOP標籤
[Intercept(typeof(ExceptionLogInterceptor))]
public class Service
{
public int TestFunction(int num1, int num2)
{
return num1 + num2;
}
}
ExceptionLogInterceptor
,就是自訂的Interceptor(攔截器),以這個例子來說,這個Interceptor是我用來處理錯誤紀錄的,如此一來,這個Service的方法都可以處理錯誤紀錄。
要使用Autofac.Extras.DynamicProxy
記得也要裝Autofac(DI Container)
更詳細的實作方法,在接下來的系列文章當中會有更加詳細的說明,請原諒我在這邊賣個關子,敬請期待。
使用AOP架構好處多多,減少重工又可以讓你的程式碼更加簡單易懂,因為共用的邏輯抽離之後,就只需要專注於商業邏輯的撰寫,只是對於C#新手來說,可能門檻比較高,不過整體來說,專案若是套用了AOP架構後,整個大升級,不管幾百幾千的方法,如果要加上一堆共用基制的話,都不用怕啦,人擋殺人,佛擋殺佛,不好意思有點激動:D
抽離共用邏輯,專注於商業邏輯
,不過因為真的很重要,多提幾次應該也無妨(?)AOP 觀念與術語
Autofac
Autofac.Extras.DynamicProxy
AOP 是不是也開放封閉原則的另一種實現呢?
之前查 AOP 的文章,範例的使用場景都是利用 AOP 來做「權限驗證、資料驗證、紀錄 Logger」。
好奇大大在實踐經驗中,會不會利用 AOP 來擴充商業邏輯呢(如:撈取 UI 所需資料)?
嗨,首先感謝你的回覆
我認為AOP也是OCP的另一種實現,例如我想修改錯誤處理的一些邏輯,只要在AOP架構中修改,而不用去改到原本的Function。
至於目前實踐的專案當中,還是先處理一些老問題(錯誤紀錄、資料驗證等),有部分客戶是有特殊需求,例如要記錄資料增刪改查的動作,但按照你所建議的,撈取UI所需資料,也許我可以透過AOP所攔截到的回傳類型與參數等資源,來回傳所需要的資料,或者傳入一段SQL語法,其他的讓AOP去解決,感謝你的建議 :D